package com.sunny.excel.util;



import com.google.common.collect.Lists;
import com.sunny.excel.annotation.ExcelCol;
import com.sunny.excel.annotation.ExcelColMap;
import com.sunny.excel.annotation.ExcelMultiCol;
import com.sunny.excel.annotation.ExcelRowNum;
import com.sunny.excel.dto.excel.ExcelColWithField;
import com.sunny.excel.dto.excel.ExcelMultiColWithField;


import java.lang.reflect.Field;
import java.util.*;

public class ExcelUtils {

    public static Map<String, ExcelColWithField> readColAsMap(Class<?> dataClass) {
        Map<String, ExcelColWithField> fieldsMap = new HashMap<>();
        List<ExcelColWithField> list = readColAsList(dataClass);
        for (ExcelColWithField field : list) {
            fieldsMap.put(field.header, field);
        }
        return fieldsMap;
    }

    public static List<ExcelColWithField> readColAsList(Class<?> dataClass) {
        List<ExcelColWithField> list = readColRec(dataClass);
        Collections.sort(list, Comparator.comparingInt(a -> a.excelCol.order()));
        return list;
    }

    private static List<ExcelColWithField> readColRec(Class<?> dataClass) {
        if (dataClass == null || dataClass == Object.class) {
            return new ArrayList<>();
        }

        List<ExcelColWithField> list = readColAsList(dataClass.getSuperclass());

        Field[] fields = dataClass.getDeclaredFields();
        for (Field field : fields) {
            ExcelCol excelCol = field.getAnnotation(ExcelCol.class);
            if (excelCol == null) {
                continue;
            }
            field.setAccessible(true);
            list.add(new ExcelColWithField(excelCol, field));
        }

        return list;
    }



    private static List<Field> getAllClassFields(Class<?> dataClass, List<Field> fields) {
        if (dataClass == null || dataClass == Object.class) {
            return fields;
        }
        Field[] declaredFields = dataClass.getDeclaredFields();
        CollectionUtils.addAll(fields, declaredFields);
        return getAllClassFields(dataClass.getSuperclass(), fields);
    }

    public static <T> Field getRowNumField(Class<T> dataClass) {
        List<Field> fields = getAllClassFields(dataClass, Lists.newArrayList());
        for (Field field : fields) {
            ExcelRowNum rowNum = field.getAnnotation(ExcelRowNum.class);
            if (rowNum != null) {
                field.setAccessible(true);
                return field;
            }
        }
        return null;
    }


    public static Map<String, ExcelMultiColWithField> readMultiColAsMap(Class<?> dataClass) {
        Map<String, ExcelMultiColWithField> fieldsMap = new HashMap<>();

        List<ExcelMultiColWithField> list = readMultiColAsList(dataClass);
        for (ExcelMultiColWithField field : list) {
            fieldsMap.put(field.header, field);
        }
        return fieldsMap;
    }

    private static List<ExcelMultiColWithField> readMultiColAsList(Class<?> dataClass) {
        List<ExcelMultiColWithField> list = readMultiColRec(dataClass);
        Collections.sort(list, Comparator.comparingInt(a -> a.excelCol.order()));

        return list;
    }


    private static List<ExcelMultiColWithField> readMultiColRec(Class<?> dataClass) {
        if (dataClass == null || dataClass == Object.class) {
            return new ArrayList<>();
        }

        List<ExcelMultiColWithField> list = readMultiColAsList(dataClass.getSuperclass());

        Field[] fields = dataClass.getDeclaredFields();
        for (Field field : fields) {
            ExcelMultiCol excelCol = field.getAnnotation(ExcelMultiCol.class);
            if (excelCol == null) {
                continue;
            }
            field.setAccessible(true);
            list.add(new ExcelMultiColWithField(excelCol, field));
        }

        return list;
    }

    public static <T> Field findDynamicFile(Class<T> dataClass) {
        if (dataClass == null || dataClass == Object.class) {
            return null;
        }
        Field[] fields = dataClass.getDeclaredFields();
        for (Field field : fields) {
            ExcelColMap excelCol = field.getAnnotation(ExcelColMap.class);
            if (excelCol != null) {
                field.setAccessible(true);
                return field;
            }
        }
        return null;
    }
}
